<?php
ini_set('display_errors',1);            //错误信息
ini_set('display_startup_errors',1);    //php启动错误信息
error_reporting(-1);                    //打印出所有的 错误信息

class WxEvent {
    private $server_url;
    private $app_id;
    private $app_secret;
    private $xml_str;

    private $msg_template = array(
        'text' => '<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[%s]]></Content></xml>',//文本回复XML模板
        'image' => '<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[image]]></MsgType><Image><MediaId><![CDATA[%s]]></MediaId></Image></xml>',//图片回复XML模板
        'music' => '<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[music]]></MsgType><Music><Title><![CDATA[%s]]></Title><Description><![CDATA[%s]]></Description><MusicUrl><![CDATA[%s]]></MusicUrl><HQMusicUrl><![CDATA[%s]]></HQMusicUrl><ThumbMediaId><![CDATA[%s]]></ThumbMediaId></Music></xml>',//音乐模板
        'news' => '<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount>%s</ArticleCount><Articles>%s</Articles></xml>',// 新闻主体
        'news_item' => '<item><Title><![CDATA[%s]]></Title><Description><![CDATA[%s]]></Description><PicUrl><![CDATA[%s]]></PicUrl><Url><![CDATA[%s]]></Url></item>',//某个新闻模板
	    'kefu' =>  '<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[%s]]></MsgType></xml>'//激活客服
    );

    public function __construct($server_url, $app_id, $app_secret, $xml_str) {
        $this->server_url = $server_url;
        $this->app_id = $app_id;
        $this->app_secret = $app_secret;
        $this->xml_str = $xml_str;
    }

    /*
     * 微信公众号事件推送回调
     */
    public function index() {
        /*
        获得请求时POST:XML字符串
        不能用$_POST获取，因为没有key
         */
        if(empty($this->xml_str)){
            die('');
        }
        if(!empty($this->xml_str)){
            // 解析该xml字符串，利用simpleXML
            libxml_disable_entity_loader(true);
            //禁止xml实体解析，防止xml注入
            $request_xml = simplexml_load_string($this->xml_str, 'SimpleXMLElement', LIBXML_NOCDATA);

            //$this->curl_post($this->server_url . '/mobile/api/v1/WxEvent.php?mode=test', array('str' => json_encode($request_xml))); // 保存事件返回数据

            //判断该消息的类型，通过元素MsgType
            switch ($request_xml->MsgType){
                case 'event':
                    //判断具体的时间类型（关注、取消、点击）
                    $event = $request_xml->Event;
                    $keyword = $request_xml->EventKey;
                    if ($keyword == 'kf') {
                        //咨询自动回复
                        $access_token = $this->getAccessToken();
                        $url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=' . $access_token;
                        $content = "您好，小马生鲜，很高兴为您服务! 高原橙49.9元10斤，下单再送1斤!点击屏幕左下角键盘标示进入咨询。";
                        $wxid =  $request_xml->FromUserName;
                        $post_msg = '{
                            "touser":"' . $wxid . '",
                                "msgtype":"text",
                                "text":
                                {
                                    "content":"' . $content . '"
                                }
                        }';
                        $this->curl_grab_page($url, $post_msg);
                        //通知客服上线
                        $to = "lifang";
                                    $message = "客户正在小马生鲜公众号平台在线咨询，请尽快登陆微信客服系统接待。";
                        $data = "to=" . $to . "&party=2&message=". $message;
                        $message_url = "http://www.xiaomashengxian.com/wxmessage.php";
                            $this->curl_post($message_url, $data);
                        $this->_msgKefu($request_xml->FromUserName, $request_xml->ToUserName);
                    }
                    if ($event=='subscribe') { // 关注事件
                        $this->doSubscribe($request_xml);
                    }elseif ($event=='unsubscribe') { // 取消关注事件
                        $this->doUnsubscribe($request_xml);
                    }elseif ($event=='LOCATION') { // 上报地理位置事件
                        $this->doLocation($request_xml);
                    }
                    elseif ($event=='SCAN') { // 已关注用户扫码事件
                        $this->doScan($request_xml);
                    }
                    break;
                case 'text'://文本消息
                    $this->doText($request_xml);
                    break;
                case 'voice'://语音消息
                    $this->doVoice($request_xml);
                    break;
                /*case 'image'://图片消息
                    $this->_doImage($request_xml);
                    break;
                case 'video'://视频消息
                    $this->_doVideo($request_xml);
                    break;
                case 'shortvideo'://短视频消息
                    $this->_doShortvideo($request_xml);
                    break;
                case 'location'://位置消息
                    $this->_doLocation($request_xml);
                    break;
                case 'link'://链接消息
                    $this->_doLink($request_xml);
                    break;*/
            }
        }
    }

    /*
     * 关注事件推送处理
     */
    private function doSubscribe($request_xml) {
        // 获取access_token
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->app_id}&secret={$this->app_secret}";
        $token_rel = json_decode(file_get_contents($url));
        // 获取用户信息
        $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$token_rel->access_token}&openid={$request_xml->FromUserName}&lang=zh_CN";
        $user_info = json_decode(file_get_contents($url));

        $data = array(
            'openid' => $request_xml->FromUserName,
            'nickname' => $user_info->nickname,
            'sex' => $user_info->sex,
            'country' => $user_info->country,
            'province' => $user_info->province,
            'city' => $user_info->city,
            'headimgurl' => $user_info->headimgurl,
            'subscribe' => $user_info->subscribe,
            'subscribe_time' => $user_info->subscribe_time,
            'language' => $user_info->language
        );

        $rel = $this->curl_post($this->server_url . '/mobile/api/v1/WxEvent.php?mode=subscribe', $data);

        // 如果是未关注用户扫码时调用相关逻辑
        if ($request_xml->Ticket) {
            $this->doSubscribeScan($request_xml);
        }

        if ($rel['data']['type'] == 1) { // 欢迎语
            $this->_msgText($request_xml->FromUserName, $request_xml->ToUserName, $rel['data']['data']);
        } else { // 新闻
            $this->_msgNews($request_xml->FromUserName, $request_xml->ToUserName, $rel['data']['data']);
        }
    }

    /**
     * 取消关注事件推送处理
     * @param $request_xml
     */
    private function doUnsubscribe($request_xml) {
        $data = array(
            'openid' => $request_xml->FromUserName
        );

        $this->curl_post($this->server_url . '/mobile/api/v1/WxEvent.php?mode=unsubscribe', $data);
        die('success');
    }

    /**
     * 已关注用户扫码事件处理
     * @param $request_xml
     */
    private function doScan($request_xml) {
        $scene_id = $request_xml->EventKey;
        $this->scan($request_xml->FromUserName, $request_xml->ToUserName, $scene_id);
    }

    /**
     * 未关注用户扫码事件处理
     * @param $request_xml
     */
    private function doSubscribeScan($request_xml) {
        $arr = explode('_', $request_xml->EventKey);
        $scene_id = $arr[1];
        $this->scan($request_xml->FromUserName, $request_xml->ToUserName, $scene_id);
    }

    private function scan($to, $from, $scene_id) {
        $rel = $this->curl_post(
            $this->server_url . '/mobile/api/v1/WxEvent.php?mode=scan',
            array('scene_id'=>$scene_id, 'openid'=>$to)
        );

        if ($rel['code'] != 200) {
            die('success');
        }

        if ($rel['data']['type'] == 1) { // 图文消息
            if (empty($rel['data']['data'])) {
                die('success');
            }
            $this->_msgNews($to, $from, $rel['data']['data']);
        } else { // 图片消息
            if (empty($rel['data']['media_id'])) {
                die('success');
            }
            $this->_msgImage($to, $from, $rel['data']['media_id']);
        }
    }

    /**
     * 上报地理位置事件处理
     * @param $request_xml
     */
    private function doLocation($request_xml) {
        $data = array(
            'openid' => $request_xml->FromUserName,
            'latitude' => $request_xml->Latitude,
            'longitude' => $request_xml->Longitude,
            'precision' => $request_xml->Precision,
        );
        $this->curl_post($this->server_url . '/mobile/api/v1/WxEvent.php?mode=location', $data);

        die('success');
    }

    /**
     * 文本消息事件处理
     * @param $request_xml
     */
    private function doText($request_xml) {
        $data = array(
            'openid' => $request_xml->FromUserName,
            'content' => $request_xml->Content
        );
        $this->curl_post($this->server_url . '/mobile/api/v1/WxEvent.php?mode=text', $data);

        die('success');
    }

    /**
     * 语音消息事件处理
     * @param $request_xml
     */
    private function doVoice($request_xml) {
        $data = array(
            'openid' => $request_xml->FromUserName,
            'content' => $request_xml->Recognition
        );
        $this->curl_post($this->server_url . '/mobile/api/v1/WxEvent.php?mode=text', $data);

        die('success');
    }
    /**
     * 激活客服
     * @param $to      目标用户ID
     * @param $from    来源用户ID
     */
    private function _msgKefu($from, $to) {
	$msgType = "transfer_customer_service";
	$response = sprintf($this->msg_template['kefu'], $from, $to, time(), $msgType);
        die($response);
    }

    /**
     * 发送文本信息
     * @param $to      目标用户ID
     * @param $from    来源用户ID
     * @param $content 内容
     */
    private function _msgText($to, $from, $content) {
        $response = sprintf($this->msg_template['text'], $to, $from, time(), $content);
        die($response);
    }

    /**
     * 发送图片信息
     * @param $to           目标用户id
     * @param $from         来源用户id
     * @param $media_id     微信图片素材标识id
     */
    private function _msgImage($to, $from, $media_id){
        $response = sprintf($this->msg_template['image'], $to, $from ,time(), $media_id);
        die($response);
    }

    /**
     * 发送新闻信息
     * @param $to
     * @param $from
     * @param array $item_list
     */
    private function _msgNews($to,$from,$item_list=array()){
        $item_str = '';
        foreach ($item_list as $item) {
            $item_str .= sprintf($this->msg_template['news_item'], $item['title'], $item['desc'], $item['picurl'], $item['url']);
        }
        //拼凑主体部分
        $response = sprintf($this->msg_template['news'], $to, $from, time(), count($item_list), $item_str);
        die($response);
    }

    /**
     * 上传图片到微信
     * @param $file
     * @param $type
     * @return bool|mix|mixed|string
     */
    private function uploadTmp($file,$type){
        $url='https://api.weixin.qq.com/cgi-bin/media/upload?access_token='.$this->getAccessToken().'&type='.$type;
        $data = array(
            'media' => '@'.$file,
        );
        $result = $this->_request('post',$url,$data);
        $result_obj = json_decode($result);
        return $result_obj;
    }

    /**
     * 获取accress_token
     * @return mixed
     */
    private function getAccessToken() {
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->app_id}&secret={$this->app_secret}";
        $token_rel = json_decode(file_get_contents($url));
        return $token_rel->access_token;
    }

    /*
     * curl post请求
     */
    private function curl_post($url, $data) {
        if (strpos($url,'https://')) {
            $rel = $this->curl_https_post($url, $data);
        } else {
            $rel = $this->curl_http_post($url, $data);
        }

        return $rel;
    }

    private function curl_grab_page($url, $data, $proxy = '', $proxystatus = '', $ref_url = ''){
	    $ch = curl_init();
	    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
	    curl_setopt($ch, CURLOPT_TIMEOUT, 1);
	    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
	    if ($proxystatus == 'true'){
		    curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, TRUE);
		    curl_setopt($ch, CURLOPT_PROXY, $proxy);
	    }
	    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
	    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	    curl_setopt($ch, CURLOPT_URL, $url);
	    if(!empty($ref_url)){
		    curl_setopt($ch, CURLOPT_HEADER, TRUE);
		    curl_setopt($ch, CURLOPT_REFERER, $ref_url);
	    }
	    curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
	    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
	    curl_setopt($ch, CURLOPT_POST, TRUE);
	    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
	    ob_start();
	    return curl_exec ($ch);
	    ob_end_clean();
	    curl_close ($ch);
	    unset($ch);
    }

    /*
     * 模拟post请求(http)
     */
    private function curl_http_post($url, $data) {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        // post数据
        curl_setopt($ch, CURLOPT_POST, 1);
        // post的变量
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

        $output = curl_exec($ch);
        curl_close($ch);

        if( preg_match('/^\xEF\xBB\xBF/', $output) ) {
            $output = substr($output,3);
        }
        $output = json_decode(trim($output), true);

        return $output;
    }

    /*
     * 模拟post请求(https)
     */
    private function curl_https_post($url, $data) {
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在
        curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
        $output = curl_exec($curl); // 执行操作
        /*if (curl_errno($curl)) {
            echo 'Errno'.curl_error($curl);//捕抓异常
        }*/
        curl_close($curl); // 关闭CURL会话

        if( preg_match('/^\xEF\xBB\xBF/', $output) ) {
            $output = substr($output,3);
        }
        $output = json_decode(trim($output), true);

        return $output;
    }
}

